/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Copyright (C) 2024-2025 Jim Gao <gaozhsoft@aliyun.com>
 *
 */
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>

#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/delay.h>

typedef struct __drv_workqueue {
    struct work_struct workstruct1;
    struct work_struct workstruct2;
    struct work_struct workstruct3;
    uint32_t num;
} DRV_WORKQUEUE;
DRV_WORKQUEUE *drv_workqueue = NULL;
static int g_drv_sleep = 0;

static void drv_workqueue_callback1(struct work_struct *data)
{
    DRV_WORKQUEUE *drv_workqueue = container_of(data, DRV_WORKQUEUE, workstruct1);
    int i = 0;
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    for (i = 0; i < 10; i++)
    {
        printk("[%s +%d %s] drv_workqueue->num=0x%x i=%d\n", __FILE__, __LINE__, __func__, drv_workqueue->num, i);
    }
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
}
static void drv_workqueue_callback2(struct work_struct *data)
{
    DRV_WORKQUEUE *drv_workqueue = container_of(data, DRV_WORKQUEUE, workstruct2);
    int i = 0;
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    for (i = 0; i < 10; i++)
    {
        printk("[%s +%d %s] drv_workqueue->num=0x%x i=%d\n", __FILE__, __LINE__, __func__, drv_workqueue->num, i);
    }
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
}
static void drv_workqueue_callback3(struct work_struct *data)
{
    DRV_WORKQUEUE *drv_workqueue = container_of(data, DRV_WORKQUEUE, workstruct3);
    int i = 0;
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    for (i = 0; i < 10; i++)
    {
        printk("[%s +%d %s] drv_workqueue->num=0x%x i=%d\n", __FILE__, __LINE__, __func__, drv_workqueue->num, i);
    }
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
}

static int __init workqueue_drv_init(void)
{
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);
    drv_workqueue = kmalloc(sizeof(DRV_WORKQUEUE), GFP_KERNEL);
    if (NULL == drv_workqueue)
    {
        printk("[%s +%d %s] kmalloc(sizeof(DRV_WORKQUEUE)) failed\n", __FILE__, __LINE__, __func__);
        return -ENOMEM;
    }
    drv_workqueue->num = 0x8090;
    printk("[%s +%d %s] drv_workqueue->num=0x%x\n", __FILE__, __LINE__, __func__, drv_workqueue->num);

    INIT_WORK(&(drv_workqueue->workstruct1), drv_workqueue_callback1);
    INIT_WORK(&(drv_workqueue->workstruct2), drv_workqueue_callback2);
    INIT_WORK(&(drv_workqueue->workstruct3), drv_workqueue_callback3);
    
    schedule_work(&(drv_workqueue->workstruct1));
    schedule_work(&(drv_workqueue->workstruct2));
    schedule_work(&(drv_workqueue->workstruct3));

    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);
    return 0;
}

static void __exit workqueue_drv_exit(void)
{
    printk("[%s +%d %s] start\n", __FILE__, __LINE__, __func__);

    if (NULL != drv_workqueue)
    {
        kfree(drv_workqueue);
        drv_workqueue = NULL;
    }
    printk("[%s +%d %s] end\n", __FILE__, __LINE__, __func__);

}

module_init(workqueue_drv_init);
module_exit(workqueue_drv_exit);

MODULE_AUTHOR("Jim Gao <gaozhsoft@aliyun.com>");
MODULE_DESCRIPTION("basic example for schedule workqueue driver");
MODULE_LICENSE("GPL v2");

